package hh.util;

import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import hh.constants.Constants;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.function.Function;

public class IoUtil {
    
    // class path
    static final ClassLoader classLoader = IoUtil.class.getClassLoader();
    static final String classPath = classLoader.getResource("").getPath();
    
    public static String getClassPath(Class clazz) {
        return clazz.getResource("/").getPath();
    }
    
    public static String getSrcPath(Class clazz) {
        return cd(clazz.getResource("/").getPath(), "../..") + "/src";
    }
    
    public static String getResourcesPath(Class clazz) {
        return cd(clazz.getResource("/").getPath(), "../..") + "/src/main/resources";
    }
    
    public static void main(String[] args) {
        List<File> list = listFiles(new File("C:\\Users\\Deepexi\\Desktop\\配置文件")
                , f -> f.isDirectory() || f.getName().endsWith(".prop"));
//        );
        System.out.println(JSONUtil.toJsonPrettyStr(list));
    }
    
    //    file
    public static List<File> listFiles(File file, Function<File, Boolean>... filters) {
        if (file == null) return new ArrayList<>(0);
        
        
        Stack<File> stack = new Stack<>();
        List<File> list = new ArrayList<>(10);
        stack.add(file);
        while (!stack.isEmpty()) {
            File pop = stack.pop();
            doListFile(stack, list, pop, filters);
        }
        return list;
    }
    
    private static void doListFile(Stack<File> stack, List<File> list, File file, Function<File, Boolean>... filters) {
        if (file.isDirectory()) {
            outer:
            for (File f : file.listFiles()) {
                if (filters != null) {
                    for (Function<File, Boolean> filter : filters) {
                        if (!filter.apply(f)) {
                            continue outer;
                        }
                    }
                }
                if (f.isDirectory()) stack.add(f);
                else list.add(f);
            }
        } else list.add(file);
    }
    
    
    
    public static String readToString(InputStream in) {
        try {
            if (in == null) {
                throw new RuntimeException("inputStream=null");
            }
            StringBuilder sb = new StringBuilder(1024);
            int defaultIoCacheSize = Constants.DEFAULT_IO_CACHE_SIZE;
            char[] chars = new char[defaultIoCacheSize];
            
            InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
            int len = 0;
            while ((len = reader.read(chars)) != -1) {
                sb.append(chars, 0, len);
            }
            return sb.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            CommonUtil.closeQuietly(in);
        }
    }
    
    public static String readSocketToString(InputStream in) {
        try {
            if (in == null) {
                throw new RuntimeException("inputStream=null");
            }
            StringBuilder sb = new StringBuilder(200);
            char[] chars = new char[100];
            
            InputStreamReader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
            int len = reader.read(chars);
            sb.append(chars, 0, len);
            return sb.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    public static String readToString(Class javaFile) {
        return readToString(javaFile.getName().replaceAll("\\.", "/") + ".java");
    }
    
    public static String readToString(String path) {
        return readToString(new File(path));
    }
    
    public static String readToString(File file) {
        String path = file.getAbsolutePath();
        try {
            if (file.exists()) {
                //绝对路径
                return readToString(new FileInputStream(file));
            }
            
            if (path.startsWith("/")) {
                path = path.substring(1);
            }
            
            InputStream in = classLoader.getResourceAsStream(path);
            if (in != null) return IoUtil.readToString(in);
            
            if (path.endsWith(".java")) {
                File f = new File(cd(classPath, "../..") + "/src/main/java/" + path);
                if (f.exists()) {
                    return readToString(new FileInputStream(f));
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return null;
    }
    
    public static String cd(String path, String cd) {
        String[] split = cd.split("/");
        if (path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }
        for (String s : split) {
            if (s.equals("..")) {
                int endIndex = path.lastIndexOf("/");
                if (endIndex == -1) {
                    break;
                }
                path = path.substring(0, endIndex);
            }
        }
        return path;
    }
    
    public static byte[] readToBytes(InputStream in) {
        
        return new byte[0];
    }
    
    public static byte[] readToBytes(ReadableByteChannel channel) {
        
        return new byte[0];
    }
    
    public static String readToString(ReadableByteChannel channel) {
        return readToString(channel, ByteBuffer.allocate(1024));
    }
    
    public static String readToString(ReadableByteChannel channel, ByteBuffer bb) {
        StringBuilder sb = new StringBuilder();
        int len = 0;
        bb.rewind();
        try {
            while ((len = channel.read(bb)) > 0) {
                sb.append(new String(bb.array()), 0, len);
                bb.rewind();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return sb.toString();
    }
    
    /**
     * class path
     */
    public static InputStream getInputStream(String path) {
        try {
            if (path.startsWith("/")) {
                if (new File(path).exists()) {
                    return new FileInputStream(path);
                }
                path = path.substring(1);
            }
            return new FileInputStream(classPath + path);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * class path
     */
    public static OutputStream getOutputStream(String path) {
        try {
            return new FileOutputStream(path);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    public static void write(String content, String path) {
        try {
            write(content, new OutputStreamWriter(new FileOutputStream(path), StandardCharsets.UTF_8));
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    
    public static void write(String content, FileOutputStream out) {
        write(content, new OutputStreamWriter(out, StandardCharsets.UTF_8));
    }
    
    public static void write(String content, OutputStreamWriter writer) {
        try {
            writer.write(content);
            writer.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            CommonUtil.closeQuietly(writer);
        }
        
    }
    
    public static Properties loadProperties(String path) {
        if (StringUtil.isEmpty(path)) return null;
        Properties properties = new Properties();
        try {
            properties.load(new InputStreamReader(new FileInputStream(path),
                    StandardCharsets.UTF_8));
            return properties;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    
    public static List<File> listFiles(List<File> list, File file) {
        if (file == null || !file.isDirectory()) return list;
        
        for (File f : file.listFiles()) {
            if (!f.isDirectory()) {
                list.add(f);
            } else listFiles(list, f);
        }
        return list;
    }
    
}
